#ifndef BFCP_MESSAGE_HXX
#define BFCP_MESSAGE_HXX

#include "BfcpTransactionMessage.hxx"
#include "BfcpNetTuple.hxx"
#include "BfcpSendData.hxx"
#include "bfcp_message_processing/bfcp_messages.h"

namespace bfcp
{
    class BfcpMessage : public BfcpTransactionMessage
    {
    public:
        BfcpMessage(int primitive, unsigned int cid, unsigned short uid, unsigned short tid, bool is_request = true);
        BfcpMessage(unsigned char *buffer, unsigned short int length, const BfcpNetTuple& source, const BfcpNetTuple& receivedTransport);
        ~BfcpMessage();

        /// Returns true if message failed to parse, false otherwise
        inline bool isInvalid() const { return !mParsedMsg; }
        /// Returns true if message is a request, false otherwise
        inline bool isRequest() const { return mRequest; }
        /// Returns true if message is a response, false otherwise
        inline bool isResponse() const { return mResponse; }

        inline bool isIncoming() const { return isFromWire(); }
        inline bool isOngoing() const { return !isFromWire(); }

        // Returns the source tuple that the message was received from
        // only makes sense for messages received from the wire
        void setSource(const BfcpNetTuple& tuple) { mSource = tuple; }
        /// @brief Returns the source tuple that the message was received from
        /// only makes sense for messages received from the wire
        const BfcpNetTuple& getSource() const { return mSource; }

        /// Used by the stateless interface to specify where to send a request/response
        void setDestination(const BfcpNetTuple& tuple) { mDestination = tuple; }
        const BfcpNetTuple& getDestination() const { return mDestination; }

        const bfcp_message* getRawMsg() const { return mRawMsg; }
        const bfcp_received_message* getParsedMsg() const { return mParsedMsg; }
        const bfcp_received_message_error* getErrors() const;
        bfcp_arguments* arguments() { return mArgs; }

        UInt16 getTransactionId() const;
        UInt32 getConferenceId() const;
        UInt16 getUserId() const;
        UInt16 getPrimitive() const;

        UInt16 getFloorStatusStatus() const;

        bool isClientTransaction() const;
        bool isFromWire() const;

        bool hasError() const;

        void flush();

        bfcp_message* copyRawData() const;

        /// output the entire message to stream
        EncodeStream& encode(EncodeStream& strm) const;
        /// output a brief description to stream
        EncodeStream& encodeBrief(EncodeStream& str) const;

    protected:
        bool parseRawMsg();
        void freeMem();

        // For messages received from the wire, this indicates information about 
        // the transport the message was received on
        BfcpNetTuple mReceivedTransportTuple;
        // For messages received from the wire, this indicates where it came
        // from. Can be used to get to the Transport and/or reliable Connection
        BfcpNetTuple mSource;
        // Used by app to specify where a message is to go
        BfcpNetTuple mDestination;

        // is a request or response
        bool mRequest;
        bool mResponse;

        /// used by incoming or ongoing message
        bfcp_message*           mRawMsg;
        /// used by incoming message
        bfcp_received_message*  mParsedMsg;
        /// used by ongoing message
        bfcp_arguments*         mArgs;
    private:
        BfcpMessage(const BfcpMessage& message);
        BfcpMessage& operator=(const BfcpMessage& rhs);
    };
}

#endif //#ifndef BFCP_MESSAGE_HXX


